//---------------------------------------------------------------------------------
#include <QtDebug>
#include <QFile>
#include <QTextStream>
#include <QTextCodec>
#include "CMap.h"
#include "CMapReader.h"
#include "CMario.h"
//---------------------------------------------------------------------------------
CMap::~CMap(void) {
	clean();
}
//---------------------------------------------------------------------------------
void CMap::draw(QPainter *painter, int x, int y, int step) {
	QMapIterator<QString, CCase *> i(cases);
	
	while (i.hasNext()) {
		int xC, yC;
		
		i.next();
		CCase *c=i.value();
		
		xC=x+c->getX()*SPRITE_WIDTH;
		yC=y+c->getY()*SPRITE_HEIGHT;
		
		c->draw(painter, xC, yC, step, c == selectedCase);
	}
	
	CMario::getInstance()->draw(painter, x+xPlayer*SPRITE_WIDTH, y+yPlayer*SPRITE_HEIGHT, step);
}
//---------------------------------------------------------------------------------
void CMap::load(QString fileName) {
	QFile *file;
	QTextStream *textStream;
	QString text="";
	
	file=new QFile(fileName);
	if(file->open(QIODevice::ReadOnly | QIODevice::Text))
	{
		textStream=new QTextStream(file);
		textStream->setCodec(QTextCodec::codecForName("utf8"));
		text=textStream->readAll();
		
		delete textStream;
		delete file;
	}
	
	CMapReader::createMap(this, text);
}
//---------------------------------------------------------------------------------
CCase* CMap::getCase(int x, int y) {
	QString key=QString::number(x)+":"+QString::number(y);
	
	if(cases.contains(key)) {
		return cases.value(key);
	}

	return 0;
}
//---------------------------------------------------------------------------------
CCase* CMap::getCase(int index) {
	if(index >= 0 && index < cases.size()) {
		QMapIterator<QString, CCase*> iM(cases);
		int i=0;
		do {
			iM.next();
			i++;
		}while (i <= index);
		
		return iM.value();
	}
	
	return 0;
}
//---------------------------------------------------------------------------------
bool CMap::addCase(CCase *c) {
	int x=c->getX();
	int y=c->getY();
	QString key=QString::number(x)+":"+QString::number(y);
	
	if(x < 0 || y < 0 || cases.contains(key)) {
		return false;
	}
	
	if(x+1 > width) {
		width=x+1;
	}
	
	if(y+1 > height) {
		height=y+1;
	}
	
	cases.insert(key, c);
	
	return true;
}
//---------------------------------------------------------------------------------
bool CMap::canMoveUp(int x, int y) {
	CCase *other=getCase(x, y-1);
	CCase *c=getCase(x, y);
	
	return canMove(c, other);
}
//---------------------------------------------------------------------------------
bool CMap::canMoveDown(int x, int y) {
	CCase *other=getCase(x, y+1);
	CCase *c=getCase(x, y);

	return canMove(c, other);
}
//---------------------------------------------------------------------------------
bool CMap::canMoveRight(int x, int y) {
	CCase *other=getCase(x+1, y);
	CCase *c=getCase(x, y);

	return canMove(c, other);
}
//---------------------------------------------------------------------------------
bool CMap::canMoveLeft(int x, int y) {
	CCase *other=getCase(x-1, y);
	CCase *c=getCase(x, y);

	return canMove(c, other);
}
//---------------------------------------------------------------------------------
bool CMap::canPushUp(int x, int y) {
	CCase *other=getCase(x, y-1);
	CCase *otherUp=getCase(x, y-2);
	CCase *c=getCase(x, y);
	
	return canPush(c, other, otherUp);
}
//---------------------------------------------------------------------------------
bool CMap::canPushDown(int x, int y) {
	CCase *other=getCase(x, y+1);
	CCase *otherDown=getCase(x, y+2);
	CCase *c=getCase(x, y);
	
	return canPush(c, other, otherDown);
}
//---------------------------------------------------------------------------------
bool CMap::canPushRight(int x, int y) {
	CCase *other=getCase(x+1, y);
	CCase *otherRight=getCase(x+2, y);
	CCase *c=getCase(x, y);
	
	return canPush(c, other, otherRight);
}
//---------------------------------------------------------------------------------
bool CMap::canPushLeft(int x, int y) {
	CCase *other=getCase(x-1, y);
	CCase *otherLeft=getCase(x-2, y);
	CCase *c=getCase(x, y);
	
	return canPush(c, other, otherLeft);
}
//---------------------------------------------------------------------------------
void CMap::clean(void) {
	QMapIterator<QString, CCase *> i(cases);
	
	while (i.hasNext()) {
		i.next();
		delete i.value();
	}
	
	cases.clear();
	width=0;
	height=0;
}
//---------------------------------------------------------------------------------
bool CMap::hasWin(void) {
	QMapIterator<QString, CCase *> i(cases);
	bool win=true;
	
	while (i.hasNext()) {
		i.next();
		if(i.value()->hasCaisse()) {
			win &= i.value()->hasEmplacement();
		}
	}
	
	return win;
}
//---------------------------------------------------------------------------------
void CMap::pushUp(void) {
	CCase *c=getCase(xPlayer, --yPlayer);
	
	c->setHasCaisse(false);
	getCase(xPlayer, yPlayer-1)->setHasCaisse(true);
}
//---------------------------------------------------------------------------------
void CMap::pushDown(void) {
	CCase *c=getCase(xPlayer, ++yPlayer);
	
	c->setHasCaisse(false);
	getCase(xPlayer, yPlayer+1)->setHasCaisse(true);
}
//---------------------------------------------------------------------------------
void CMap::pushRight(void) {
	CCase *c=getCase(++xPlayer, yPlayer);
	
	c->setHasCaisse(false);
	
	getCase(xPlayer+1, yPlayer)->setHasCaisse(true);
}
//---------------------------------------------------------------------------------
void CMap::pushLeft(void) {
	CCase *c=getCase(--xPlayer, yPlayer);
	
	c->setHasCaisse(false);
	getCase(xPlayer-1, yPlayer)->setHasCaisse(true);
}
//---------------------------------------------------------------------------------
void CMap::setSelectedCase(int x, int y) {
	selectedCase=getCase(x, y);
}
//---------------------------------------------------------------------------------
CMap* CMap::clone(void) {
	CMap* mapC=new CMap();
	QMapIterator<QString, CCase *> i(cases);
	int xP, yP;
	
	while (i.hasNext()) {
		i.next();
		CCase* c=i.value();
		CCase* cC=new CCase(c->getX(), c->getY(), c->getCaseType());
		cC->setHasCaisse(c->hasCaisse());
		cC->setHasEmplacement(c->hasEmplacement());
		
		mapC->addCase(cC);
	}
	
	getPlayerPos(xP, yP);
	mapC->setPlayerPos(xP, yP);
	
	return mapC;
}
//---------------------------------------------------------------------------------
bool CMap::canMove(CCase *o, CCase *d) {
	if(o == 0 || d == 0) {
		return false;
	}
	
	if(d->getCaseType() == CCase::ectMur || d->hasCaisse()) {
		return false;
	}
	
	return true;
}
//---------------------------------------------------------------------------------
bool CMap::canPush(CCase *o, CCase *d, CCase *ds) {
	if(o == 0 || d == 0 || ds == 0 || !d->hasCaisse() || !canMove(d, ds)) {
		return false;
	}
	
	return true;
}
//---------------------------------------------------------------------------------